/* X KeySym definitions.  Add more at will. */
#include <Python.h>
#include "gtktester_lowlevel_x11.h"
#include "gtktestermodule.h"
#include <string.h>
#include <X11/Xlib.h>
#include <X11/extensions/XTest.h>
#include <X11/keysymdef.h>
#include <gdk/gdkx.h>

keysymdef syms[171] = {{"BackSpace", XK_BackSpace},
                      {"Tab", XK_Tab},
                      {"Linefeed", XK_Linefeed},
                      {"Return", XK_Return}, 
                      {"Pause", XK_Pause},
                      {"Scroll_Lock", XK_Scroll_Lock},
                      {"Sys_Req", XK_Sys_Req},
                      {"Escape", XK_Escape},
                      {"Delete", XK_Delete},
                      {"Home", XK_Home},
                      {"Left", XK_Left},
                      {"Up", XK_Up},
                      {"Right", XK_Right},
                      {"Down", XK_Down},
                      {"Page_Up", XK_Page_Up},
                      {"Page_Down", XK_Page_Down},
                      {"End", XK_End},
                      {"KP_Home", XK_KP_Home},
                      {"KP_Left", XK_KP_Left},
                      {"KP_Up", XK_KP_Up},
                      {"KP_Right", XK_KP_Right},
                      {"KP_Down", XK_KP_Down},
                      {"KP_Prior", XK_KP_Prior},
                      {"KP_Page_Up", XK_KP_Page_Up},
                      {"KP_Next", XK_KP_Next},
                      {"KP_Page_Down", XK_KP_Page_Down},
                      {"KP_End", XK_KP_End},
                      {"KP_Begin", XK_KP_Begin},
                      {"KP_Insert", XK_KP_Insert},
                      {"KP_Delete", XK_KP_Delete},
                      {"KP_Equal", XK_KP_Equal},
                      {"KP_Multiply", XK_KP_Multiply},
                      {"KP_Add", XK_KP_Add},
                      {"KP_Separator", XK_KP_Separator},
                      {"KP_Subtract", XK_KP_Subtract},
                      {"KP_Decimal", XK_KP_Decimal},
                      {"KP_Divide", XK_KP_Divide},
                      {"KP_0", XK_KP_0},
                      {"KP_1", XK_KP_1},
                      {"KP_2", XK_KP_2},
                      {"KP_3", XK_KP_3},
                      {"KP_4", XK_KP_4},
                      {"KP_5", XK_KP_5},
                      {"KP_6", XK_KP_6},
                      {"KP_7", XK_KP_7},
                      {"KP_8", XK_KP_8},
                      {"KP_9", XK_KP_9},
                      {"F1", XK_F1},
                      {"F2", XK_F2},
                      {"F3", XK_F3},
                      {"F4", XK_F4},
                      {"F5", XK_F5},
                      {"F6", XK_F6},
                      {"F7", XK_F7},
                      {"F8", XK_F8},
                      {"F9", XK_F9},
                      {"F10", XK_F10},
                      {"F11", XK_F11},
                      {"L1", XK_L1},
                      {"F12", XK_F12},
                      {"Shift_L", XK_Shift_L},
                      {"Shift_R", XK_Shift_R},
                      {"Control_L", XK_Control_L},
                      {"Control_R", XK_Control_R},
                      {"Caps_Lock", XK_Caps_Lock},
                      {"Shift_Lock", XK_Shift_Lock},
                      {"Meta_L", XK_Meta_L},
                      {"Meta_R", XK_Meta_R},
                      {"Alt_L", XK_Alt_L},
                      {"Alt_R", XK_Alt_R},
                      {"Super_L", XK_Super_L},
                      {"Super_R", XK_Super_R},
                      {"Hyper_L", XK_Hyper_L},
                      {"Hyper_R", XK_Hyper_R},
                      {" ", XK_space},
                      {"!", XK_exclam},
                      {"quotedbl", XK_quotedbl},
                      {"#", XK_numbersign},
                      {"$", XK_dollar},
                      {"%", XK_percent},
                      {"&", XK_ampersand},
                      {"'", XK_apostrophe},
                      {"quoteright", XK_quoteright},
                      {"(", XK_parenleft},
                      {")", XK_parenright},
                      {"*", XK_asterisk},
                      {"+", XK_plus},
                      {",", XK_comma},
                      {"-", XK_minus},
                      {".", XK_period},
                      {"/", XK_slash},
                      {"0", XK_0},
                      {"1", XK_1},
                      {"2", XK_2},
                      {"3", XK_3},
                      {"4", XK_4},
                      {"5", XK_5},
                      {"6", XK_6},
                      {"7", XK_7},
                      {"8", XK_8},
                      {"9", XK_9},
                      {":", XK_colon},
                      {";", XK_semicolon},
                      {"<", XK_less},
                      {"=", XK_equal},
                      {">", XK_greater},
                      {"?", XK_question},
                      {"@", XK_at},
                      {"A", XK_A},
                      {"B", XK_B},
                      {"C", XK_C},
                      {"D", XK_D},
                      {"E", XK_E},
                      {"F", XK_F},
                      {"G", XK_G},
                      {"H", XK_H},
                      {"I", XK_I},
                      {"J", XK_J},
                      {"K", XK_K},
                      {"L", XK_L},
                      {"M", XK_M},
                      {"N", XK_N},
                      {"O", XK_O},
                      {"P", XK_P},
                      {"Q", XK_Q},
                      {"R", XK_R},
                      {"S", XK_S},
                      {"T", XK_T},
                      {"U", XK_U},
                      {"V", XK_V},
                      {"W", XK_W},
                      {"X", XK_X},
                      {"Y", XK_Y},
                      {"Z", XK_Z},
                      {"[", XK_bracketleft},
                      {"\\", XK_backslash},
                      {"]", XK_bracketright},
                      {"asciicircum", XK_asciicircum},
                      {"_", XK_underscore},
                      {"grave", XK_grave},
                      {"quoteleft", XK_quoteleft},
                      {"a", XK_a},
                      {"b", XK_b},
                      {"c", XK_c},
                      {"d", XK_d},
                      {"e", XK_e},
                      {"f", XK_f},
                      {"g", XK_g},
                      {"h", XK_h},
                      {"i", XK_i},
                      {"j", XK_j},
                      {"k", XK_k},
                      {"l", XK_l},
                      {"m", XK_m},
                      {"n", XK_n},
                      {"o", XK_o},
                      {"p", XK_p},
                      {"q", XK_q},
                      {"r", XK_r},
                      {"s", XK_s},
                      {"t", XK_t},
                      {"u", XK_u},
                      {"v", XK_v},
                      {"w", XK_w},
                      {"x", XK_x},
                      {"y", XK_y},
                      {"z", XK_z},
                      {"{", XK_braceleft},
                      {"bar", XK_bar},
                      {"}", XK_braceright},
                      {"asciitilde", XK_asciitilde}};

static int KeyDescriptionToKeysym (const char *description)
{
	int i;
	for (i = 0; i < 171; i++)
		if (!strcmp (description, syms[i].key))
			return syms[i].value;
	return 0;
}

int lowlevel_pressKey (const char *key)
/* Returns TRUE on success */
{
	int ksym = KeyDescriptionToKeysym (key);
	Display *dpy = GDK_DISPLAY();
	KeyCode kc = 0;
	if (ksym == 0) {
		return FALSE;
	}

	kc = XKeysymToKeycode(dpy, ksym);
	if (kc == 0) {
		return FALSE;
	}
	XTestFakeKeyEvent(dpy, kc, TRUE, CurrentTime);
	XTestFakeKeyEvent(dpy, kc, FALSE, 20);
	return TRUE;
}

void lowlevel_click (unsigned int button)
{
	Display *dpy = GDK_DISPLAY();
	XTestFakeButtonEvent(dpy, button, TRUE, 0);
	XTestFakeButtonEvent(dpy, button, FALSE, 0);
	return;
}

void lowlevel_movePointerTo (int dst_x, int dst_y)
{
	int x, y, delay;
	Display *dpy = GDK_DISPLAY();
	lowlevel_getPointerCoords (&x, &y);
	delay = 1;
	while (x != dst_x || y != dst_y) {
		if (dst_x != x) (dst_x > x ? x++ : x--);
		if (dst_y != y) (dst_y > y ? y++ : y--);
		XTestFakeMotionEvent(dpy, -1, x, y, delay);
		gtktester_yield_internal();
	}
	gtktester_wait_internal (delay);
	return;
}

void lowlevel_getWidgetGeometry (GtkWidget *widget, gint *x, gint *y, gint *width, gint *height)
{
	gdk_window_get_position (widget->window, x, y);
	if (GTK_WIDGET_NO_WINDOW (widget)) {
		*x += widget->allocation.x;
		*y += widget->allocation.y;
		*width = widget->allocation.width;
		*height = widget->allocation.height;
	}
	else {
		gdk_drawable_get_size (GDK_DRAWABLE (widget->window), width, height);	
	}
	return;
}

int lowlevel_getPointerCoords (int *x, int *y)
{
	int root_x_return, root_y_return, win_x_return, win_y_return;
	unsigned int mask_return;
	Display *dpy = GDK_DISPLAY();
	Window w = GDK_ROOT_WINDOW(), root_return, child_return;
	if (!XQueryPointer(dpy, w, &root_return, &child_return, &root_x_return, &root_y_return, &win_x_return, &win_y_return, &mask_return)) {
    	return 0;
    }
    else {
    	*x = root_x_return;
    	*y = root_y_return;
    }
    return 1;
}

